package org.grc.app.z_project.z_framework.util;

import java.io.File;
import java.io.FileFilter;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** 
 * 类操作工具类
 * 
 * @author grc
 * @since 1.0-SNAPSHOT
 */
public class ClassUtil {

	private static final Logger LOGGER = LoggerFactory.getLogger(ClassUtil.class);
	
	/**
	 * 获取类加载器
	 */
	public static ClassLoader getClassLoader(){
		return Thread.currentThread().getContextClassLoader();
	}

    /**
     * 获取类路径
     */
	public static String getClassPath(){
		String classPath = "";
		URL resource = getClassLoader().getResource("");
		if (resource != null) {
			classPath = resource.getPath();
		}
		return classPath;
	}
	
    /**
     * 加载类（将自动初始化）
     */
    public static Class<?> loadClass(String className) {
        return loadClass(className, true);
    }
    
    /**
     * 加载类
     */
    public static Class<?> loadClass(String className, boolean isInitialized) {
        Class<?> cls;
        try {
            cls = Class.forName(className, isInitialized, getClassLoader());
        } catch (ClassNotFoundException e) {
            LOGGER.error("加载类出错！", e);
            System.out.println("加载类出错！");
            throw new RuntimeException(e);
        }
        return cls;
    }
    
    /**
     * 是否为 int 类型（包括 Integer 类型）
     */
    public static boolean isInt(Class<?> clazz) {
        return clazz.equals(int.class) || clazz.equals(Integer.class);
    }

    /**
     * 是否为 long 类型（包括 Long 类型）
     */
    public static boolean isLong(Class<?> clazz) {
        return clazz.equals(long.class) || clazz.equals(Long.class);
    }

    /**
     * 是否为 double 类型（包括 Double 类型）
     */
    public static boolean isDouble(Class<?> clazz) {
        return clazz.equals(double.class) || clazz.equals(Double.class);
    }

    /**
     * 是否为 String 类型
     */
    public static boolean isString(Class<?> clazz) {
        return clazz.equals(String.class);
    }
    
    /**
     * 获取指定报名下的所有类
     */
    public static Set<Class<?>> getClassSet (String packageName) {
    	// 较为复杂的是获取指定包名下的所有类，我们需要根据包名并将其转换为文件路径。
    	// 读取class文件或者jar包，获取指定的类名去加载类。
    	Set<Class<?>> classSet = new HashSet<Class<?>>();
    	try {
    		Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/"));
    		while (urls.hasMoreElements()) {
    			URL url = urls.nextElement();
    			if (url != null) {
    				String protocol = url.getProtocol();
    				if (protocol.equals("file")) {
    					String packagePath = url.getPath().replaceAll("%20", " ");
    					addClass(classSet, packagePath, packageName);
    				}
    				else if (protocol.equals("jar")) {
    					JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
    					if (jarURLConnection != null) {
    						JarFile jarFile = jarURLConnection.getJarFile();
    						if (jarFile != null) {
    							Enumeration<JarEntry> jarEntries = jarFile.entries();
    							while (jarEntries.hasMoreElements()) {
    								JarEntry jarEntry = jarEntries.nextElement();
    								String jarEntryName = jarEntry.getName();
    								if (jarEntryName.endsWith(".class")) {
    									String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
//    									System.out.println(className);
    									doAddClass(classSet, className);
    								}
    							}
    						}
    					}
    				}
    			}
    		}
    	} catch (Exception e) {
    		LOGGER.error("get class set failure", e);
    		throw new RuntimeException(e);
    	}
    	return classSet;
    }
    
    // 获取Class对象到classSet
    private static void addClass (Set<Class<?>> classSet, String packagePath, String packageName) {
    	File[] files = new File(packagePath).listFiles(new FileFilter() {
			@Override
			public boolean accept(File file) {
				// 找出两类文件 class文件和文件夹
				return (file.isFile() && file.getName().endsWith(".class") || file.isDirectory());
			}
		});
    	for (File file : files) {
    		String fileName = file.getName();
    		// 如果是文件
    		if (file.isFile()) {
    			String className = fileName.substring(0,fileName.lastIndexOf("."));
    			if (StringUtil.isNotEmpty(packageName)) {
    				className = packageName + "." + className;
    				doAddClass(classSet, className);
    				showLoadClassInfo(className);
    			}
    		}
    		// 不是文件（文件夹）
    		else {
    			String subPackagePath = fileName;
    			if (StringUtil.isNotEmpty(packagePath)) {
    				subPackagePath = packagePath + "/" + subPackagePath;
    			}
    			String subPackageName = fileName;
    			if (StringUtil.isNotEmpty(packageName)) {
    				subPackageName = packageName + "." +subPackageName;
    			}
    			// 递归调用addClass方法
    			addClass(classSet, subPackagePath, subPackageName);
    		}
    	}
    }
    
    // 加载类，并且加到classSet。
    private static void doAddClass (Set<Class<?>> classSet, String className) {
    	// isInitialized = false
    	Class<?> clazz = loadClass(className, Boolean.FALSE);
    	classSet.add(clazz);
    }
    
    // 显示加载类信息
    private static void showLoadClassInfo (String className) {
		LOGGER.info("load class: " + className);
    }
}
